#include "pulses.h"

#define PULSE_MAX_DURATION      (5000)
#define PULSE_MAX               (32)
#define PULSE_SAMPLE_INTV_USEC  (10)
#define PULSE_CAPTURE_END       ((uint16_t)-1)

// -----------------------------
// about pulse receiving and compress
// -----------------------------
//@param[in] signalseq the pulse seq build up by durations: hi->low->hi->low->... and termimated with a 0xffff
//@param[out] out the compressed result: out->seq[0+] top 4bits of each byte is the hi sig multiplier based on short_dur, 
//                                       low 4bits the low sig multipler. if the multipler is greater than 0x8, the pair of
//                                       plus will expand to two bytes leading by a 0x80 flag
bool PulseSeq_compress(uint16_t* captureBuf, uint16_t usecSampleIntv, PulseSeq* out)
// bool Pulse_compress(volatile PulseCaptureBuf* in, PulseSeq* out)
{
	// find out the three most sig in the seq, and determ the short-signal
	uint16_t shortS=0xffff, tmp1=0xffff, tmp2=0xffff;
	int i =0, j =0;
	bool bLongPulse =FALSE;

	if (NULL == captureBuf)
		return FALSE;

	if (NULL == out || NULL == out->seq || out->seqlen <10)
		return FALSE;

	for (i =0; captureBuf[i] != PULSE_CAPTURE_END; i++)
	{
		if (tmp2 > captureBuf[i])
		{
			if (tmp1 > captureBuf[i])
			{
				if (shortS > captureBuf[i])
					shortS = captureBuf[i];
				else tmp1 = captureBuf[i];

				continue;
			}

			tmp2 = captureBuf[i];
		}
	}

	if (shortS <=0)
	{
		shortS = tmp1; tmp1=tmp2; tmp2=0xffff;
	}

	if (tmp1 < (shortS <<1))
	{
		if (tmp2 < (shortS <<1))
			shortS = (shortS + (tmp1 <<3) + tmp2 +5)/10;
		else shortS = (shortS + (tmp1 <<3)+4)/9;
	}

	if (captureBuf[0] <(shortS>>2) && captureBuf[1] <(shortS>>2))
		return FALSE;

	out->short_durXusec = shortS;
	i =0; j =0;
	while (captureBuf[i] != PULSE_CAPTURE_END && j < (out->seqlen -2))
	{
		bLongPulse =FALSE;
		tmp1 = captureBuf[i++] + (shortS>>2);
		tmp1 /= shortS;
		bLongPulse = (tmp1 >=8) ?TRUE :FALSE;
		if (tmp1 >= 0x80 || captureBuf[i] == (uint16_t)(-1))
		{
			out->seq[j] = 0xff;
			break;
		}

		tmp2 = captureBuf[i++] + (shortS>>2);
		tmp2 /= shortS;
		bLongPulse = (bLongPulse || (tmp2 >=8)) ?TRUE :FALSE;
		if (tmp2 >= 0x80 || captureBuf[i] == (uint16_t)(-1))
		{
			out->seq[j] = 0xff;
			break;
		}

		if (bLongPulse)
		{
			out->seq[j++] = 0x80 | tmp1;
			out->seq[j++] = 0x80 | tmp2;
		}
		else
			out->seq[j++] = (tmp1 <<4) | tmp2;
	}

	out->short_durXusec *= usecSampleIntv;
//	in->timeout = 0; // the parsed capture result is no more useful

	out->seqlen = j;
	return (j>8)? TRUE :FALSE;
}

bool Pulses_capture(uint16_t* captureBuf, uint8_t captureBufLen, uint16_t usecSampleIntv, ReadPin_f readPin)
{
	volatile uint16_t maxdur =0, *p=NULL;
	uint8_t i, maxpulses;
	bool done=FALSE;
	if (NULL == captureBuf || captureBufLen <=2 || NULL ==readPin)
		return FALSE;

	if (usecSampleIntv <50)
		usecSampleIntv =50;

	maxpulses = (captureBufLen -2) /2;

	maxdur = PULSE_1_PL_MAX_DUR_MSEC *1000 /usecSampleIntv;	// no single pulse should be more than 80msec

	for (i=0, done=FALSE; !done && i <maxpulses; i++)
	{
		p = &captureBuf[i*2];
		for (*p = (50/usecSampleIntv) +1; !done && 0 ==readPin();) 
		{
			if ((*p)++ > maxdur)
			{ done=TRUE; break; }

			delayXusec(usecSampleIntv);
		}

		for (*(p+1) = *p, p++; !done && readPin();) 
		{
			if ((*p)++ > maxdur)
			{ done=TRUE; break; }

			delayXusec(usecSampleIntv);
		}
	}

	*(++p) =PULSE_CAPTURE_END; *(++p) =PULSE_CAPTURE_END;

	if ((p - captureBuf) <20)
		return FALSE;

	return TRUE;
}

/*
 bool Pulse_capture(volatile PulseCaptureBuf* out, ReadPin_f readPin)
{
	uint16_t maxdur =0, *p=NULL;
	uint8_t i, maxpulses;
	bool done=FALSE;
	if (NULL == out || NULL == out->buf || out->bufLen <=2 || NULL ==readPin)
		return FALSE;

	if (out->timeout--)
		return FALSE;

	if (out->sampleIntvXusec <50)
		out->sampleIntvXusec =50;

	out->timeout =0;
	maxpulses = (out->bufLen -2) /2;

	maxdur = PULSE_1_PL_MAX_DUR_MSEC *1000 /out->sampleIntvXusec;	// no single pulse should be more than 80msec

	for (i=0, done=FALSE; !done && i <maxpulses; i++)
	{
		p = &out->buf[i*2];
		for (*p = (50/out->sampleIntvXusec) +1; !done && 0 ==readPin();) 
		{
			if ((*p)++ > maxdur)
			{ done=TRUE; break; }

			delayXusec(out->sampleIntvXusec);
		}

		for (*(p+1) = *p, p++; !done && readPin();) 
		{
			if ((*p)++ > maxdur)
			{ done=TRUE; break; }

			delayXusec(out->sampleIntvXusec);
		}
	}

	*(++p) =0xffff; *(++p) =0xffff;

	if ((p - out->buf) <20)
		return FALSE;

	out->timeout = PULSE_CapturedData_Timeout;
	return TRUE;
}
*/

// -----------------------------
// The keyboard via Wiegand26
// -----------------------------
//@usecSample the interval of sample in usec
//@readDX     callback to read the signal pin D0 or D1
//@hasSig     callback to read if either D0 or D1	has signals

#define WGPINVAL(_DX) (_DX?1:0)	 // convert the value of DX to value bit
bool Pulse_readWiegand26(volatile uint32_t* pCode, uint8_t usecSample, ReadPin_f readDX, ReadPin_f hasSig)
{
	int i=0, j;
	uint8_t tmp;

	if (usecSample <=10)
		usecSample =10;

	*pCode = 0;
	for (i=0; i < 26; i++)
	{
		// step 1. test if there is input signal
		for (j = (int) PULSE_1_PL_MAX_DUR_MSEC *1000/usecSample; j>0 && !hasSig(); j--)
		{
			delayXusec(usecSample);
		}

		if (j<=0)
			return FALSE;

		// step 2 read one pin
		tmp = readDX();

		// filter the noise
		delayXusec(usecSample*2);
		if (tmp != readDX())
			return FALSE;

		// test if it is a long signal
		for (j = (int) PULSE_1_PL_MAX_DUR_MSEC *1000/usecSample; j>0; j--)
		{
			if (tmp != readDX())
				break;

			delayXusec(usecSample);
		}

		if (j<=0)
			return FALSE;

		// valid signal here
		*pCode <<=1;
		*pCode |= WGPINVAL(tmp);
	}

	return TRUE;
}

// ======================================================================
// Pulse codecs
// ======================================================================

typedef void (*PulseEncoder)(uint32_t code, PulseSeq* out, uint8_t isRepeat);
typedef bool (*PulseDecoder)(const PulseSeq* in, uint32_t* pCode);

static void PulseEncode_PT2262(uint32_t code, PulseSeq* out, uint8_t isRepeat);
static bool PulseDecode_PT2262(const PulseSeq* in, uint32_t* pCode);

static void PulseEncode_EV1527(uint32_t code, PulseSeq* out, uint8_t isRepeat);
static bool PulseDecode_EV1527(const PulseSeq* in, uint32_t* pCode);

#ifdef STM32
// the following will be cancelled by covered by PulseSend_byProfile
void IOSend_uPD6121(const IO_PIN* pin, bool HeqH, uint32_t code);
void IOSend_PT2262(const IO_PIN* pin, bool HeqH, uint32_t code);
void IOSend_TC9012F(const IO_PIN* pin, bool HeqH, uint32_t code);
void IOSend_M7461M(const IO_PIN* pin, bool HeqH, uint32_t code);
#endif // STM32

typedef struct _PulseCodecNode
{
	uint8_t profId;
	const char* profName;
	PulseEncoder encoder;
	PulseDecoder decoder;
} PulseCodecNode;

static const PulseCodecNode __pulse_profiles__[] = {
	{ PulseProfId_PT2262_EV1527, "PT2262_EV1527", PulseEncode_EV1527, PulseDecode_EV1527 },
	{ PulseProfId_uPD6121,       "uPD6121",       PulseEncode_PT2262, PulseDecode_PT2262 },
	{ PulseProfId_TC9012F,       "TC9012F",       PulseEncode_PT2262, PulseDecode_PT2262 },
	{ PulseProfId_M7461M,        "M7461M",        PulseEncode_PT2262, PulseDecode_PT2262 },

	{ PulseProfId_UNKNOWN,       "UNKONWN", NULL, NULL },
	{ PulseProfId_MAX,           NULL, NULL, NULL },
};

uint8_t	Pulse_findProfId(const char* profname)
{
	uint8_t i;
	if (NULL == profname)
		return PulseProfId_UNKNOWN;

	for (i=0; i< PulseProfId_UNKNOWN && __pulse_profiles__[i].profName; i++)
	{
		if (NULL != strstr(__pulse_profiles__[i].profName, profname))
			return i;
	}

	return PulseProfId_UNKNOWN;
}

const char*	Pulse_profName(uint8_t profId)
{
	if (profId > PulseProfId_UNKNOWN)
		profId = PulseProfId_UNKNOWN;

	return __pulse_profiles__[profId].profName;
}

bool Pulses_encodeEx(const PulseCode* in, PulseSeq* out, uint8_t isRepeat)
{
	int i;
	if (NULL ==in || NULL == out || NULL == out->seq)
		return FALSE;

	for (i=0; __pulse_profiles__[i].profId < PulseProfId_UNKNOWN; i++)
	{
		if (in->profId == __pulse_profiles__[i].profId)
		{
			if (NULL != __pulse_profiles__[i].encoder)
			{
				__pulse_profiles__[i].encoder(in->code, out, isRepeat);
				out->short_durXusec = in->short_durXusec;
				return TRUE;
			}

			break;
		}
	}

	return FALSE;
}

bool Pulses_encode(PulseSeq* out, const uint32_t code, uint8_t profileId, uint16_t short_durXusec, uint8_t isRepeat)
{
	PulseCode in;
	if (profileId >= PulseProfId_UNKNOWN)
		return FALSE;

	in.profId         = profileId;
	in.code           = code;
	in.short_durXusec = short_durXusec;

	return Pulses_encodeEx(&in, out, isRepeat);
}

bool Pulses_decodeEx(const PulseSeq* in, PulseCode* out)
{
	int i;
	if (NULL ==in || NULL == in->seq || NULL == out)
		return FALSE;

	for (i=0; __pulse_profiles__[i].profId < PulseProfId_UNKNOWN; i++)
	{
		if (NULL == __pulse_profiles__[i].decoder)
			continue;

		if (__pulse_profiles__[i].decoder(in, &out->code))
		{
			out->profId = __pulse_profiles__[i].profId;
			out->short_durXusec = in->short_durXusec;
			return TRUE;
		}
	}

	return FALSE;
}

bool Pulses_decode(const PulseSeq* in, uint32_t* pCode, uint8_t* pProfId, uint16_t* pShort_durXusec)
{
	PulseCode out;
	if (NULL == pCode || NULL == in || NULL == in->seq)
		return FALSE;

	if (!Pulses_decodeEx(in, &out))
		return FALSE;

	*pCode = out.code;

	if (NULL != pProfId)
		*pProfId = out.profId;
	
	if (NULL !=pShort_durXusec)
		*pShort_durXusec  = out.short_durXusec;
		
	return TRUE;
}



// -----------------------------
// PulseEncode_PT2262()
// -----------------------------
void PulseEncode_PT2262(uint32_t code, PulseSeq* out, uint8_t isRepeat)	// recommend to repeat six times when sending
{
	int i =0;
	uint8_t tmp=0;
	if (NULL==out || NULL == out->seq)
		return;

	// the sync signal: H=4*a, L=(128-4)*a
	out->seqlen = 0; out->seq[out->seqlen++] = 0x80 +1; out->seq[out->seqlen++] = 0x80 +32;

	// PT2262 takes 8bit address + 4bit data code, but each bit has three state: '0','1','f'
	// so we assign 2bit for each bit: '0'-00b, '1'-11b, 'f'-01b
	for (i =0; i<12; i++, code <<=2)
	{
		tmp = (code >>22) &0x33;
		switch (tmp)
		{
		case 0: // '0': H=4*a, L=12*a, H=4*a, L=12*a
			out->seq[out->seqlen++] = (1<<4) | 4;  out->seq[out->seqlen++] = (1<<4) | 4;
			break;
		case 0x3: // '1': H=12*a, L=4*a, H=12*a, L=4*a
			out->seq[out->seqlen++] = (3<<4) | 4;  out->seq[out->seqlen++] = (3<<4) | 4;
			break;
		default: // 'f': H=4*a, L=12*a, H=12*a, L=4*a
			out->seq[out->seqlen++] = (1<<4) | 4;  out->seq[out->seqlen++] = (3<<4) | 4;
			break;
		}
	}

	out->seq[out->seqlen++] =0x80; out->seq[out->seqlen++] = 216 - 32 - 4*12;
	out->seq[out->seqlen] =0xff;
	out->short_durXusec = 560; // the default min dur is 0.56msec
}

// -----------------------------
// PulseDecode_PT2262()
// -----------------------------
#define IS_PULSE_A(_PL)	        ((_PL) >=0x13 && (_PL) <= 0x15)  // H=4*a, L=12*a,
#define IS_PULSE_B(_PL)	        ((_PL) >=0x23 && (_PL) <= 0x45)	 //	H=12*a, L=4*a,

bool PulseDecode_PT2262(const PulseSeq* in, uint32_t* pCode)
{
	uint8_t* pPulse=NULL;
	int i = 0;
	if (NULL == pCode || NULL==in || NULL == in->seq || in->seqlen <26)
		return FALSE;

	*pCode =0;
	pPulse = in->seq;

	// locate the sync signal: H=4*a, L=(128-4)*a, shift over there
	for (i=in->seqlen-26; i>0; i--, pPulse++)
	{
		if (0xff == *pPulse)
			return FALSE;

		if (*pPulse>0x80 && *pPulse<0x83 && *(pPulse+1)>(0x80+20) && *(pPulse+1)<(0x80+60) && (IS_PULSE_A(*(pPulse+2)) || IS_PULSE_B(*(pPulse+2))))
			break;
	}

	if (i <=0)
		return FALSE;

	pPulse++; pPulse++;

	// PT2262 takes 8bit address + 4bit data code, but each bit has three state: '0','1','f'
	// so we assign 2bit for each bit: '0'-00b, '1'-11b, 'f'-01b
	for (i = 12; i >0; i--, pPulse++, pPulse++)
	{
		// the '0': H=4*a, L=12*a, H=4*a, L=12*a
		if (IS_PULSE_A(*pPulse) && IS_PULSE_A(*(pPulse+1)))
		{ *pCode <<=2; continue; }

		// the '1': H=12*a, L=4*a, H=12*a, L=4*a
		if (IS_PULSE_B(*pPulse) && IS_PULSE_B(*(pPulse+1)))
		{ *pCode <<=2; *pCode |=3; continue; }

		// the 'f': H=4*a, L=12*a, H=12*a, L=4*a
		if (IS_PULSE_A(*pPulse) && IS_PULSE_B(*(pPulse+1)))
		{ *pCode <<=2; *pCode |=1; continue; } 

		// exception occurred if reach here
		break;
	}

	return (i==0)? TRUE:FALSE;
}

// -----------------------------
// PulseEncode_EV1527()
// -----------------------------
void PulseEncode_EV1527(uint32_t code, PulseSeq* out, uint8_t isRepeat)	// recommend to repeat six times when sending
{
	int i=0;
	if (NULL==out || NULL == out->seq)
		return;

	// the sync signal: H=a, L=(32-1)*a
	out->seqlen = 0; out->seq[out->seqlen++] = 0x80 +1; out->seq[out->seqlen++] = 0x80 +32;

	// 20bit address + 4bit data code
	for (i =24; i>0; i--, code <<=1)
	{
		if (code & (1<<23))
		{
			// the '1': H=3*a, L=a
			out->seq[out->seqlen++] = (3<<4) | 4;
			continue;
		}

		// the '0': H=a, L=3*a
		out->seq[out->seqlen++] = (1<<4) | 4;
	}

	out->seq[out->seqlen++] =0x80; out->seq[out->seqlen++] = 216 - 32 - 4*12;
	out->seq[out->seqlen] =0xff;
	out->short_durXusec = 560; // the default min dur is 0.56msec
}

// -----------------------------
// PulseDecode_EV1527()
// -----------------------------
bool PulseDecode_EV1527(const PulseSeq* in, uint32_t* pCode)
{
	uint8_t* pPulse=NULL;
	int i = 0;
	if (NULL == pCode || NULL==in || NULL == in->seq || in->seqlen <26)
		return FALSE;

	*pCode =0;
	pPulse = in->seq;

	// the sync signal: H=a, L=(32-1)*a
	for (i=in->seqlen-26; i>0; i--, pPulse++)
	{
		if (0xff == *pPulse)
			return FALSE;

		if (in->seq[0] <0x80 || in->seq[0]>0x83 || in->seq[1]>(0x80+60) || in->seq[1]<(0x80+20))
			break;
	}

	if (i <=0)
		return FALSE;

	pPulse++; pPulse++;

	// 20bit address + 4bit data code
	for (i = 24; i >0; i--, pPulse++)
	{
		// the '0': H=a, L=3*a
		if (IS_PULSE_A(*pPulse))
		{ *pCode <<=1; continue; }

		if (IS_PULSE_B(*pPulse))
		{ *pCode <<=1; *pCode |=1; continue; }

		// exception occurred if reach here
		return FALSE;
	}

	return (i==26)? TRUE:FALSE;
}

// ======================================================================
// About pulse sending
// ======================================================================
uint8_t PulseSeq_send(PulseSeq* in, SetPulsePin_f sender)
{
	int i=0;
	uint8_t hdur, ldur;
	if (NULL ==in || in->short_durXusec<=0 || NULL==sender)
		return 0;

	for (i=0; i < in->seqlen; i++)
	{
		if (0xff == in->seq[i])
			break;

		if (in->seq[i] & 0x80)
		{
			hdur = in->seq[i++] & 0x7f;
			ldur = in->seq[i] & 0x7f -hdur;
		}
		else
		{
			hdur = in->seq[i] >>4;
			ldur = in->seq[i] & 0xf - hdur;
		}

		if (hdur >0)
		{
			sender(1);
			delayXusec(in->short_durXusec * hdur);
		}

		if (ldur >0)
		{
			sender(0);
			delayXusec(in->short_durXusec * hdur);
		}

	}

	return i;
}

uint8_t seq[50];
PulseSeq pulses = {50, 0, seq};

bool PulseCode_send(PulseCode* in, SetPulsePin_f sender, uint8_t repeatTimes)
{
	if (NULL ==in || NULL==sender)
		return FALSE;

	pulses.seqlen = sizeof(seq) -2;
	if (!Pulses_encodeEx(in, &pulses, 0))
		return FALSE;

	if (!PulseSeq_send(&pulses, sender))
		return FALSE;

	if (repeatTimes <=0)
		return TRUE;

	Pulses_encodeEx(in, &pulses, 1);
	for (; repeatTimes >0; repeatTimes--)
	{
		if (!PulseSeq_send(&pulses, sender))
			break;
	}
	return TRUE;
}


#ifdef _STM32F10X

#define IRRecvRead(_PORT, _PIN) (GPIO_ReadInputDataBit(_PORT, _PIN) ? 0:1)

// out[0] keeps the min duration of plus, out[1] keeps the number of plus in the sequence
int IRRecv(const IO_PIN* pin, int8_t out[], int8_t maxLen)
{
	int i, minDur;
	int16_t signals[PULSE_MAX*2];
	// int8_t  out[MAX_PLUS+2]; 

	minDur = min(maxLen -2, PULSE_MAX); // temporary save as the max length that can receive
	if (minDur <=0)
		return out[1]=0;

	// receive the plus into signals[]
	for (out[1]=0; out[1]<minDur; out[1]++)
	{
		for (i=0; i<PULSE_MAX_DURATION && 1 == IRRecvRead(pin->port, pin-pin); i++)
			delayXusec(PULSE_SAMPLE_INTV_USEC);
		signals[2*out[1]] = i;
		if (i >= PULSE_MAX_DURATION)
			break;

		for (i=0; i<PULSE_MAX_DURATION && 0 ==IRRecvRead(pin->port, pin-pin); i++)
			delayXusec(PULSE_SAMPLE_INTV_USEC);
		signals[2*out[1]+1] = i;
		if (i >= PULSE_MAX_DURATION)
			break;
	}

	// compress the plus sequence
	// step 1. find out the L with minimal duration, keep the value in minDur
	minDur = PULSE_MAX_DURATION;
	for (i=0; i< out[1]; i++)
	{
		if (signals[2*i] >2 && signals[2*i] < minDur)
			minDur = signals[2*i];
	}

	// step 2. divide each duration with the minimal duration and save it in out[2+]
	for (i=0; i< out[1]; i++)
		out[i+2] = (signals[2*i] + signals[2*i+1] + minDur/2) / minDur;

	// step 3. save minDur in out[0] by adjusting the unit to 0.1msec
	out[0] = minDur * PULSE_SAMPLE_INTV_USEC / 100;

	return out[1];
}

// ======================================================================
// about pulse sending
// ======================================================================
static int32_t _pulseusec =0;

static int pulsei, pulsej;
static uint32_t pulseWkcode;

#define clockWLx10usec   (10)

#define sendPulseF(_X_PIN, HeqH, _durH, _durL) \
     { if (HeqH) GPIO_SetBits(_X_PIN->port, _X_PIN->pin);   else GPIO_ResetBits(_X_PIN->port, _X_PIN->pin); delayXusec(_durH); \
	   if (HeqH) GPIO_ResetBits(_X_PIN->port, _X_PIN->pin); else GPIO_SetBits(_X_PIN->port, _X_PIN->pin);   delayXusec(_durL); \
	   _pulseusec +=_durH+_durL; }

#define beginFrame(_code)          { _pulseusec =0; pulseWkcode=_code; }

#define endFrame(_durFrame) \
     { _pulseusec = _durFrame -_pulseusec-100; if (_pulseusec>0) delayXusec(_pulseusec); _pulseusec=0; }

// -----------------------------
// PulseSend_bySeq()
// -----------------------------
void PulseSend_bySeq(const IO_PIN* pin, bool HeqH, PulseSeq* in)
{
	int i=0;
	if (NULL ==in || NULL == in->seq)
		return;

	for(; i< in->seqlen && in->seq[i] !=0xff; i++)
	{
		if (in->seq[i] >0x80)
		{
			//hidur  = (int32_t) in->baseIntvX10usec * in->short_dur * (0x7f & in->seq[i]);
			//lowdur = (int32_t) in->baseIntvX10usec * in->short_dur * (0x7f & in->seq[++i]);
			sendPulseF(pin, HeqH, 
				(int32_t) in->short_durXusec * (0x7f & in->seq[i]),
				(int32_t) in->short_durXusec * (0x7f & in->seq[++i]));

			if (0xff == in->seq[i])
				break;
		}
		else
		{
			//			hidur  = (int32_t) in->baseIntvX10usec * in->short_dur * (in->seq[i] >>4);
			//			lowdur = (int32_t) in->baseIntvX10usec * in->short_dur * (in->seq[i] & 0x0f);
			sendPulseF(pin, HeqH, 
				(int32_t) in->short_durXusec * (in->seq[i] >>4),
				(int32_t) in->short_durXusec * (in->seq[i] & 0x0f));
		}
	}
}

// -----------------------------
// struct PulseSend_Profile
// -----------------------------
typedef struct _PulseSend_Profile
{
	char*    name;
	uint8_t  baseIntvX10usec; // in 10 usec
	uint8_t  bitsCount;  // number of data bits in one message 
	uint8_t  sigLeading[2], sigZero[4], sigOne[4], sigRepeat[2]; // duration of H/L mutified with sampleInterval
	uint16_t flags; // b0-3 repeatCount, b4-pulse_firstL
} PulseSend_Profile;

// -----------------------------
// _PulseSend_Profiles: the known profiles
// -----------------------------
const static PulseSend_Profile _PulseSend_Profiles[] =
{
	{"uPD6121G", 56, 32, {16,8}, {1,1,0,0}, {1,3,0,0}, {40,1}, 0x07 },	  // D3 = /D2
	{"TC9012F",  56, 32, {8,8},  {1,1,0,0}, {1,3,0,0}, {40,1}, 0x07 },	  // D3 = /D2
	{"M50560",   50, 16, {8,8},  {1,1,0,0}, {1,3,0,0}, {40,1}, 0x47 },	
	{"LC7461M",  56, 32, {16,8}, {1,1,0,0}, {1,3,0,0}, {40,1}, 0x07 },	  // D1=/D0, D3=/D2
	{"PT2262",   56, 12, {1,31}, {1,3,1,3}, {3,1,3,1}, {0,140}, 0x06 },
	{"EV1527",   56, 24, {1,31}, {1,3,0,0}, {3,1,0,0}, {0,140}, 0x06 },
	{NULL,        0,  0, {0,0},  {0,0,0,0}, {0,0,0,0}, {0,0},  0x00 }	  // NULL terminator
};

// -----------------------------
// PulseSend_byProfileId()
// -----------------------------
void PulseSend_byProfileId(uint8_t profileId, uint32_t code, const IO_PIN* pin, uint8_t HeqH, uint32_t baseIntvXusec)
{
	int i=0, j=0;
	const PulseSend_Profile* profile = NULL;
	if (NULL == pin || profileId > (sizeof(_PulseSend_Profiles)/sizeof(PulseSend_Profile) -2))
		return;
	
	profile = &_PulseSend_Profiles[profileId];
	HeqH = HeqH ? 1:0;
	HeqH ^= (profile->flags >>4) & 0x01;

	if (0==baseIntvXusec)
		baseIntvXusec = ((uint32_t) profile->baseIntvX10usec) *10;

	// the repeat loop
	for (i=0; i <= (profile->flags & 0xf); i++)
	{
		if (0==i) // the leading signal
			{sendPulseF(pin, HeqH, baseIntvXusec * profile->sigLeading[0], baseIntvXusec * profile->sigLeading[1]);}
		else // the repeat signal
			{sendPulseF(pin, HeqH, baseIntvXusec * profile->sigRepeat[0], baseIntvXusec * profile->sigRepeat[1]);}

		// sending the bits, MSMF
		for (j=0; j < profile->bitsCount; j++, code>>=1)
		{
			if (code &1)
			{
				// send the "1"
				sendPulseF(pin, HeqH, baseIntvXusec * profile->sigOne[0], baseIntvXusec * profile->sigOne[1]);

				if (0 == profile->sigOne[2])
					continue;

				sendPulseF(pin, HeqH, baseIntvXusec * profile->sigOne[2], baseIntvXusec * profile->sigOne[3]);
			}
			else
			{
				// send the "0"
				sendPulseF(pin, HeqH, baseIntvXusec * profile->sigZero[0], baseIntvXusec * profile->sigZero[1]);

				if (0 == profile->sigOne[2])
					continue;

				sendPulseF(pin, HeqH, baseIntvXusec * profile->sigZero[2], baseIntvXusec * profile->sigZero[3]);
			}
		}

	}
}


// -----------------------------
// PulseSend_byProfile()
// -----------------------------
void PulseSend_byProfile(char* profileName, uint32_t code, const IO_PIN* pin, uint8_t HeqH, uint32_t baseIntvXusec)
{
	uint8_t profId=0;
	for (profId=0; NULL != _PulseSend_Profiles[profId].name && 0 != strcmp(_PulseSend_Profiles[profId].name, profileName); profId++);
	PulseSend_byProfileId(profId, code, pin, HeqH, baseIntvXusec);
}

void IOSend_uPD6121(const IO_PIN* pin, bool HeqH, uint32_t code)
{
	for (pulsej=0; pulsej <6; pulsej++) // repeat six times by default
	{
		beginFrame(code);

		if (pulsej>0)
		{
			// send the repeat signal
			sendPulseF(pin, HeqH, 9000, 2250);	
		}
		else  sendPulseF(pin, HeqH, 9000, 4500); // send the lead signal

		// 8bit address + 4bit data code, every bit takes 2bit of code: 0=00, 1=01, f=11
		for (pulsei=32; pulsei>0; pulsei--)
		{
			if (pulseWkcode & 0x1)
			{ sendPulseF(pin, HeqH, 560, 2250-560); } // send the '1': H=0.56ms, L=2.250-0.56msec
			else { sendPulseF(pin, HeqH, 560, 1125-560); } // send the '0': H=0.56ms, L=1.125-0.56msec

			pulseWkcode <<=1;
		}

		endFrame(108000); // time of frame =108msec
	}

}

void IOSend_TC9012F(const IO_PIN* pin, bool HeqH, uint32_t code)
{
	for (pulsej=0; pulsej <6; pulsej++) // repeat six times by default
	{
		beginFrame(code);

		if (pulsej>0)
		{
			// send the repeat code
			_pulseusec =0;
			sendPulseF(pin, HeqH, 4500, 4500);	
			if (pulseWkcode & 0x1)
				{ sendPulseF(pin, HeqH, 560, 1125-560); }
			else { sendPulseF(pin, HeqH, 560, 2250-560); }
		}
		else sendPulseF(pin, HeqH, 4500, 4500); // send the lead signal: H=4.5ms, L=4.5ms

		// 8bit address + 4bit data code, every bit takes 2bit of code: 0=00, 1=01, f=11
		for (pulsei=32; pulsei>0; pulsei--)
		{
			if (pulseWkcode & 0x1)
			{ sendPulseF(pin, HeqH, 560, 2250-560); } // send the '1': H=0.56ms, L=2.250-0.56msec
			else { sendPulseF(pin, HeqH, 560, 1125-560); } // send the '0': H=0.56ms, L=1.125-0.56msec

			pulseWkcode <<=1;
		}

		endFrame(108000); // time of frame =108msec
	}
}

void IOSend_M7461M(const IO_PIN* pin, bool HeqH, uint32_t code)
{
	for (pulsej=0; pulsej <6; pulsej++) // repeat six times by default
	{
		beginFrame(code);

		if (pulsej>0)
		{
			// send the repeat signal H=9ms, L=4.5ms
			_pulseusec =0;
			sendPulseF(pin, HeqH, 9000, 4500);
		}
		else sendPulseF(pin, HeqH, 9000, 4500); // send the lead signal: H=9ms, L=4.5ms

		// 8bit address + 4bit data code, every bit takes 2bit of code: 0=00, 1=01, f=11
		for (pulsei=32; pulsei>0; pulsei--)
		{
			if (pulseWkcode & 0x1)
			{ sendPulseF(pin, HeqH, 560, 2250-560); } // send the '1': H=0.56ms, L=2.250-0.56msec
			else { sendPulseF(pin, HeqH, 560, 1125-560); } // send the '0': H=0.56ms, L=1.125-0.56msec

			pulseWkcode <<=1;
		}

		endFrame(108000); // time of frame =108msec
	}
}

#endif // STM32
